package com.web.farme;


import com.web.farme.annotation.EnableCreateTable;
import com.web.farme.component.DatabaseHandler;
import com.web.farme.component.DefaultDatabaseHandler;
import com.web.farme.config.*;
import com.web.farme.tool.BeanRegistryUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author : bi
 * @since : 2021年06月30日
 */
@Slf4j
public class MysqlAutoConfigRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private List<DataSourceConfig> datasourceConfigList;
    private ConfigurableEnvironment environment;
    private final List<Object> autoCreateInfoList = new ArrayList<>();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(EnableCreateTable.class.getName()));
        Assert.notNull(annotationAttributes, "Annotation can not be null");
        this.loadProperties();
        this.loadDataSources();

        BeanDefinitionBuilder mysqlAutoCreate = BeanDefinitionBuilder.rootBeanDefinition(MysqlAutoCreate.class);
        mysqlAutoCreate.addPropertyValue("autoCreateInfoList", this.autoCreateInfoList);
        BeanRegistryUtils.registerBeanDefinition(registry, mysqlAutoCreate.getBeanDefinition(), MysqlAutoCreate.class.getSimpleName());
        BeanDefinitionBuilder datasourceHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultDatabaseHandler.class);
        BeanRegistryUtils.registerBeanDefinition(registry, datasourceHandler.getBeanDefinition(), DatabaseHandler.class.getSimpleName());

    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }

    private void loadProperties() {
        this.datasourceConfigList = getDynamicSourceConfigMap(DynamicSourceConfig.class);
        Assert.notNull(this.datasourceConfigList, "配置文件装载错误");
    }

    private void loadDataSources() {
        for (DataSourceConfig dataSourceConfig : this.datasourceConfigList) {
            //目前没有分布式
            NormalAutoCreateInfo normalAutoCreateInfo = new NormalAutoCreateInfo();
            normalAutoCreateInfo.setDataSourceName(dataSourceConfig.getName());
            normalAutoCreateInfo.setScanEntityPackages(dataSourceConfig.getEntityPackage());
            normalAutoCreateInfo.setDataSourceConfig(dataSourceConfig);
            this.autoCreateInfoList.add(normalAutoCreateInfo);
        }
    }


    public <T extends DefaultConfig> List<DataSourceConfig> getDynamicSourceConfigMap(Class<T> tClass) {
        T t = null;
        try {
            t = tClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        Binder binder = Binder.get(this.environment);
        assert t != null;
        List<DataSourceConfig> resultList = new ArrayList<>();
        Map<String, Datasource> datasourceMap = binder.bind(t.getConfigKey(), Bindable.mapOf(String.class, Datasource.class)).get();
        for (Map.Entry<String, Datasource> entry : datasourceMap.entrySet()) {
            Datasource datasource = entry.getValue();
            DataSourceConfig dataSourceConfig = new DataSourceConfig();
            BeanUtils.copyProperties(datasource, dataSourceConfig);
            dataSourceConfig.setName(entry.getKey());
            resultList.add(dataSourceConfig);
        }
        return resultList;

    }
}
